package util

import (
	"crypto/md5"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"hash/crc32"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"time"
)

// 文件执行目录
func FileBasePath() (string, error){
	BasePath, err := exec.LookPath(os.Args[0])
	if err != nil {
		//fmt.Println(err)
		return "", err
	}
	//    Is Symlink
	fi, err := os.Lstat(BasePath)
	if err != nil {
		//fmt.Println(err)
		return "", err
	}
	if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
		BasePath, err = os.Readlink(BasePath)
		if err != nil {
			//fmt.Println(err)
			return "", err
		}
	}
	execDir := filepath.Dir(BasePath)
	if execDir == "." {
		execDir, err = os.Getwd()
		if err != nil {
			//fmt.Println(err)
			return "", err
		}
	}
	return BasePath, nil
}


//读取文件
func FileReadAll(fileName string)  ([]byte, error)  {
	return ioutil.ReadFile(fileName)
}
// 判断所给路径文件/文件夹是否存在
func FileExists(path string) bool {
	_, err := os.Stat(path)    //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}


//调用os.MkdirAll递归创建文件夹
func FileCreateFile(filePath string)  error  {
	if !FileIsExist(filePath) {
		err := os.MkdirAll(filePath,os.ModePerm)
		return err
	}
	return nil
}


// 判断所给路径文件/文件夹是否存在(返回true是存在)
func FileIsExist(path string) bool {
	_, err := os.Stat(path)    //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}



func CopyRemoteFile(remoteFile,targetFile, host, user, pwd string)(int, error){
	config := &ssh.ClientConfig{
		User:user,
		Auth: []ssh.AuthMethod{
			ssh.Password(pwd),
		},
		Timeout:         30 * time.Second,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}
	client, err := ssh.Dial("tcp", host + ":22", config)
	if err != nil {
		return -1, fmt.Errorf("connect server error: %w", err)
	}
	sfile, err1 := sftp.NewClient(client)
	if err1 != nil {
		return -1, fmt.Errorf("new sftp client error: %w", err1)
	}
	source, err := sfile.Open(remoteFile)
	if err != nil {
		return -1, fmt.Errorf("sftp client open file error: %w", err)
	}
	defer source.Close()
	targetDir := filepath.Dir(targetFile)
	FileCreateFile(targetDir)
	target, err := os.OpenFile(targetFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
	if err != nil {
		return -1, fmt.Errorf("open local file error: %w", err)
	}
	defer target.Close()
	n, err := io.Copy(target, source)
	if err != nil {
		return -1, fmt.Errorf("write file error: %w", err)
	}
	return int(n), nil
}

func CopyFile( originalFile,targetFile string)error{
	source,err := os.Open(originalFile)
	if err != nil{
		return fmt.Errorf("open originalFile file error: %w", err)
	}
	defer source.Close()
	targetDir := filepath.Dir(targetFile)
	FileCreateFile(targetDir)
	target, err1 := os.OpenFile(targetFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777)
	if err1 != nil{
		return fmt.Errorf("open targetFile file error: %w", err1)
	}
	defer target.Close()
	_, err2 := io.Copy(target, source)
	if err2 != nil {
		return fmt.Errorf("write file error: %w", err2)
	}
	return nil
}

func Unzip(filePath string) {
	cmd := exec.Command("unzip", "-o", filePath, "-d", filepath.Dir(filePath))
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	err := cmd.Start()
	if err != nil{
		fmt.Println(err.Error())
	}
	cmd.Wait()
}


func ClearDir(path string){
	cmd := exec.Command("rm", "-rf", path + string(os.PathSeparator) + "*")
	fmt.Println(path + string(os.PathSeparator) + "*")
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	err := cmd.Start()
	if err != nil{
		fmt.Println(err.Error())
	}
	err = cmd.Wait()
	if err != nil{
		fmt.Println(err.Error())
	}
}

func Crc32Hash(val string) string {
	return strconv.FormatUint(uint64(crc32.ChecksumIEEE([]byte(val))), 16)
}



func GetFilehash(path string) (hash string) {
	file, err := os.Open(path)
	if err!= nil{
		return ""
	}
	defer file.Close()
	h_ob := sha256.New()
	_, err1 := io.Copy(h_ob, file)
	if err1 == nil {
		hash := h_ob.Sum(nil)
		hashvalue := hex.EncodeToString(hash)
		return hashvalue
	} else {
		return ""
	}
}

func GetFileMd5(path string) (hash string) {
	data, err := ioutil.ReadFile(path)
	if err!= nil{
		return ""
	}
	value := md5.Sum(data)
	return  fmt.Sprintf("%x", value)

}